package com.yps.io.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class ClientHandle implements Runnable{

	private String host;
	private int port;
	private Selector selector;
	private SocketChannel socketChannel;
	private volatile boolean started;
	
	public ClientHandle(String ip, int port) {
		this.host = ip;
		this.port = port;
		try {//初始化选择器和打开通道
			selector = Selector.open();
			//打开监听通道
			socketChannel = SocketChannel.open();
			//开启费阻塞
			socketChannel.configureBlocking(false);
			started = true;//标记开启
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		}
	}
	
	public void stop() {
		started = false;
	}
	@Override
	public void run() {
		try {
			doConnect();//连接是否正常
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		}
		while (started) {
			try {
				//无论有无读写事件发生，都唤醒一次selector
				selector.select(1000);
				//也可以只有当至少一个注册的事件发生的时间才会继续
//				selector.select();
				//获得选择器当前的keys
				Set<SelectionKey> keys = selector.selectedKeys();
				Iterator<SelectionKey> it = keys.iterator();
				SelectionKey selectionKey = null;
				while (it.hasNext()) {
					selectionKey = (SelectionKey) it.next();
					it.remove();
					try {
						handleInput(selectionKey);//处理服务端返回
					} catch (Exception e) {
						if(selectionKey != null){
							selectionKey.cancel();
							if(selectionKey.channel() != null){
								selectionKey.channel().close();
							}
						}
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
				System.exit(1);
			}
		}
		//当selector关闭后会自动释放管理里面的资源
		if(selector !=null){
			try {
				selector.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	private void handleInput(SelectionKey key) throws IOException {
		if(key.isValid()){
			SocketChannel sc = (SocketChannel) key.channel();
			if(key.isConnectable()){
				if(!sc.finishConnect()){
					System.exit(1);
				}
			}
			//读取消息，
			if(key.isReadable()){
				ByteBuffer buffer = ByteBuffer.allocate(1024);
				int readBytes = sc.read(buffer);
				if(readBytes>0){
					//将缓存区当前的limit设置为position = 0 ， 用于后续对缓冲区的读取操作
					buffer.flip();
					//根据缓存区可读字节创建数组
					byte[] bytes = new byte[buffer.remaining()];
					//将缓冲去可读字节数组复制到新建的数组中
					buffer.get(bytes);
					String result = new String(bytes, "UTF-8");
					System.out.println("客户端收到消息：" + result);
				}else if(readBytes<0){
//					关闭链路，释放资源
					key.cancel();
					sc.close();
				}
			}

			
		}
	}

	private void doConnect() throws IOException {
		if(!socketChannel.connect(new InetSocketAddress(host, port))){
			socketChannel.register(selector, SelectionKey.OP_CONNECT);
		}
	}

	public void sendMsg(String msg) throws IOException {
		socketChannel.register(selector, SelectionKey.OP_READ);
		doWrite(socketChannel, msg);
	}

	private void doWrite(SocketChannel channel, String requst) throws IOException {
		byte[] bytes = requst.getBytes();
		//根据数组容量创建ByteBuffer
		ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);
		//将字节数组复制到缓冲区
		writeBuffer.put(bytes);
		//flip操作
		writeBuffer.flip();
		channel.write(writeBuffer);
	};
}
